package businessLogic;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.*;

import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.*;

public class AutomatedAssistant
{
	public final static String LIBRARY_COUNTY = "Springfield";
	public final static double LIBRARY_FEE$ = 10.0;

	public AutomatedAssistant() 
	{
	}

	public AutomatedAssistant(String membersFilename, String catalogFilename, String transactionsFilename) throws NumberFormatException, ParseException
	{
		this.membersFilename = membersFilename;
		this.catalog = new Catalog(catalogFilename);
		this.transactionRecords = new TransactionRecords(transactionsFilename);
		this.loadMembers();
	}

	private void loadMembers() throws ParseException 
	{
		File file = new File(this.membersFilename);
		try
		{
			Scanner scanner = new Scanner (file);

			while (scanner.hasNextLine())
			{
				String line = scanner.nextLine();
				Member member = new Member(line, this.catalog, this.transactionRecords);
				String memberId = member.getMemberId();
				this.libraryMembers.put(memberId, member);
			}     
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}     
	}

	public void persistLibrary() throws IOException
	{
		this.transactionRecords.persistTransactionRecords();
		this.catalog.persistCatalogItems();
		this.persistMembers();
	}

	private void persistMembers() throws IOException 
	{
		File membersFile = new File(this.membersFilename);
		FileWriter fWriter = new FileWriter(membersFile);
		BufferedWriter writer = new BufferedWriter(fWriter);

		for (Map.Entry<String, Member> entry : this.libraryMembers.entrySet())
		{
			Member member = entry.getValue();
			String line = member.serializeMember();
			writer.write(line);
			writer.newLine();
		}

		writer.close();	
	}

	public ArrayList<Item> searchItems(String searchQuery)
	{
		return catalog.findItems(searchQuery);
	}

	public Collection<Item> itemCheckout(String memberId, String itemId)
	{
		Collection<Item> checkedOutItems = new ArrayList<Item>();


		Member member = this.libraryMembers.get(memberId);
		Item item = catalog.getItem(itemId);
		String itemType = item.getType();

		if(!member.isEligibleToCheckout(itemType))
		{
			return checkedOutItems;
		}

		if(!item.isAvailableForCheckout())
		{
			String message = "The item you have requested is either checked-out or reserved by another member. Please try again later";
			String title = "ITEM UNAVAILABLE FOR CHECKOUT";
			JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);
			return checkedOutItems;
		}

		item.checkout();
		checkedOutItems = member.checkout(itemId, item);

		Transaction newTransaction = this.transactionRecords.add("TT_CHECKOUT_ITEM", memberId, itemId, 0.0);
		member.addTransaction(newTransaction);
		return checkedOutItems; 
	}

	public double itemReturn(String memberId, String itemId)
	{

		Item item = catalog.getItem(itemId);
		double fine = item.returnItem();

		Member member = this.libraryMembers.get(memberId);
		member.returnItem(itemId, fine);

		Transaction newTransaction = this.transactionRecords.add("TT_RETURN_ITEM", memberId, itemId, fine);
		member.addTransaction(newTransaction);

		String message = "You have successfully returned item <" + itemId + ">. The fine on this item is <" + fine + ">";
		String title = "ITEM SUCCESSFULLY RETURNED";
		JOptionPane.showMessageDialog(null, message, title, JOptionPane.PLAIN_MESSAGE);

		return fine;
	}

	public double itemLost(String memberId, String itemId)
	{

		Item item = catalog.getItem(itemId);
		item.lost();
		double fine = item.getPrice();

		String message = "Please pay a fine of $" + fine + " for the LOST-ITEM <" + itemId + ">";
		String title = "ITEM-LOST FINE NOTICE";
		JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);

		Member member = this.libraryMembers.get(memberId);
		member.returnItem(itemId, fine);

		Transaction newTransaction = this.transactionRecords.add("TT_LOST_ITEM", memberId, itemId, fine);
		member.addTransaction(newTransaction);

		return fine;
	}

	public Collection<Item> itemReserve(String memberId, String itemId)
	{
		Collection<Item> reservedItems = new ArrayList<Item>();

		Member member = this.libraryMembers.get(memberId);

		Item item = catalog.getItem(itemId);

		if(!item.isAvailableForReserve())
		{
			String message = "The item you have requested is either currently available for check-out or already reserved by another member";
			String title = "ITEM UNAVAILABLE FOR RESERVING";
			JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);
			return reservedItems;
		}

		item.reserve();
		reservedItems = member.reserve(itemId, item);

		Transaction newTransaction = this.transactionRecords.add("TT_RESERVE_ITEM", memberId, itemId, 0.0);
		member.addTransaction(newTransaction);

		return reservedItems; 
	}

	public String registerNewMember(String name, String address, String emailId)
	{
		/*if(!address.equalsIgnoreCase(AutomatedAssistant.LIBRARY_COUNTY))
		{
			String message = "Please Pay Fee of " + AutomatedAssistant.LIBRARY_FEE$ + " to become a member";
			String title = "OUT OF COUNTY FEES";
			int selectedOption = JOptionPane.showConfirmDialog(null, message, title, JOptionPane.OK_CANCEL_OPTION);
			if(selectedOption == JOptionPane.OK_OPTION)
				JOptionPane.showMessageDialog(null, "Thank you for your payment", "PAYMENT RECEIVED", JOptionPane.PLAIN_MESSAGE);
			else
				return null;
		}*/

		Random rnd = new Random();
		int length = 5;
		char[] text = new char[length];
		for (int i = 0; i < length; i++)
		{
			text[i] = emailId.charAt(rnd.nextInt(emailId.length()));
		}

		String newMemberId = new String(text);
		Member newMember = new Member(newMemberId, name, address, emailId);
		this.libraryMembers.put(newMemberId, newMember);

		Transaction newTransaction = this.transactionRecords.add("TT_NEW_MEMBER", newMemberId, "", 0.0); 
		newMember.addTransaction(newTransaction);

		return newMemberId;
	}

	public double payFine(String memberId, double fineAmount)
	{

		Member member = this.libraryMembers.get(memberId);
		double remainingFine = member.payFine(fineAmount);

		Transaction newTransaction = this.transactionRecords.add("TT_PAY_FINE", memberId, "", fineAmount);
		member.addTransaction(newTransaction);
		return remainingFine;
	}

	public ArrayList<Transaction> showTransactionHistory(String memberId, Date startDate, Date endDate)
	{
		Member member = this.libraryMembers.get(memberId);
		if(startDate == null || endDate == null)
			return member.getTransactionHistory();
		else
			return member.getTransactionHistory(startDate, endDate);
	}

	public boolean validateAdminCredentials(String username, String password)
	{
		Administrator adminTemp = new Administrator();
		if(!adminTemp.validateCredentials(username, password))
		{
			String message = "You have entered Incorrect Admin Credentials (Username/Password). Please check and retry";
			String title = "INVALID ADMINISTRATOR";
			JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);
			return false;
		}

		this.admin = adminTemp;
		return true;
	}

	public Map<String, Integer> totalNoOfBooksAndVideosinLibrary()
	{
		return catalog.totalNoOfBooksAndVideosinLibrary();
	}
	public int totalNoOfMembers()
	{
		return this.libraryMembers.size();
	}
	public int noOfItemsBorrowed()
	{
		return catalog.getNoOfItemsBorrowed();
	}
	public Map<String, Integer> bookCheckedOutTheMost(Date startDate, Date endDate)
	{
		Map<String, Integer> itemsCheckedOutTheMostById = transactionRecords.bookCheckedOutTheMost(startDate, endDate);

		Map<String, Integer> itemsCheckedOutTheMostByIdAndTitle = new HashMap<String, Integer>();
		for (Map.Entry<String,Integer> entry : itemsCheckedOutTheMostById.entrySet())
		{
			String itemId = entry.getKey();
			Integer count = entry.getValue();
			Item item = this.catalog.getItem(itemId);
			String title = item.getTitle();

			itemsCheckedOutTheMostByIdAndTitle.put(itemId + ":" + title, count);
		}

		return itemsCheckedOutTheMostByIdAndTitle;
	}

	public double getTotalFineAmount(Date startDate, Date endDate)
	{
		return transactionRecords.getTotalFineAmount(startDate, endDate);
	}
	public boolean validateMember(String memberId)
	{
		if (!libraryMembers.containsKey(memberId))
		{
			String message = "You have entered an Incorrect Member-ID <" + memberId + "> Please check and retry";
			String title = "INVALID MEMBER-ID";
			JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);
			return false;
		}
		return true;
	}
	public boolean validateItem(String itemId)
	{
		if(!catalog.isAValidItem(itemId))
		{
			String message = "You have entered an Incorrect Item-ID <" + itemId + "> Please check and retry";
			String title = "INVALID ITEM-ID";
			JOptionPane.showMessageDialog(null, message, title, JOptionPane.OK_OPTION);
			return false;
		}
		return true;

	}
	Catalog catalog;
	TransactionRecords transactionRecords;
	String membersFilename;
	HashMap<String, Member> libraryMembers = new HashMap<String, Member>();
	Administrator admin;
}
